package com.ehotting.edsta.gateway.filter;

import com.ehotting.eaf.core.utils.StringUtils;
import com.ehotting.edsta.gateway.config.properties.IgnoreSignProperties;
import com.ehotting.edsta.gateway.config.properties.IgnoreWhiteProperties;
import io.netty.buffer.UnpooledByteBufAllocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;

@Component
public class CachePostBodyFilter implements GlobalFilter, Ordered {

    // 排除过滤的 uri 地址，nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;

    @Autowired
    private IgnoreSignProperties ignoreSign;

    /*@PostConstruct
    public void init(){
        // 跳过驱动程序B端请求
        ignoreWhite.getWhites().add("/driverAdapt/project/rePostByBrowser");
        // 跳过驱动程序上传请求
        ignoreWhite.getWhites().add("/driverAdapt/project/rePostUploadByBrowser");
        ignoreWhite.getWhites().add("/driverAdapt/project/rePostUpload");
        // 导入元器件文件接口
        ignoreWhite.getWhites().add("/circuitDesign/element/importExcel");
        // 添加规则
        ignoreWhite.getWhites().add("/circuitDesign/script/addAll");
        ignoreWhite.getWhites().add("/circuitDesign/circuit/importExcel");

        // 信号分析
        ignoreWhite.getWhites().add("/signalAnalysis/signalAnalysis/getAnalysisResult");

    }*/

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest();

        // 跳过不需要验证的路径

        String url = serverHttpRequest.getURI().getPath();

        if (StringUtils.isMatch("/file/**", url)
//                || StringUtils.isMatch("/system/**", url)
                || StringUtils.isMatch("/code/**", url)
                || StringUtils.matches(url, ignoreWhite.getWhites())
                || StringUtils.matches(url, ignoreSign.getIgnores())) {
            return chain.filter(exchange);
        }

        HttpMethod method = serverHttpRequest.getMethod();
        if (this.requiresBody(method)) {
            ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
            Mono<String> bodyToMono = serverRequest.bodyToMono(String.class);
            return bodyToMono.flatMap(body -> {
                exchange.getAttributes().put("cachedRequestBody", body);
                ServerHttpRequest newRequest = new ServerHttpRequestDecorator(serverHttpRequest) {
                   
                    @Override
                    public Flux<DataBuffer> getBody() {
                        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
                        DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(body.getBytes());
                        return Flux.just(bodyDataBuffer);
                    }
                };
                return chain.filter(exchange.mutate().request(newRequest).build());
            });
        }
        return chain.filter(exchange);
    }

    private boolean requiresBody(HttpMethod method) {
        switch(method) {
            case PUT:
            case POST:
            case PATCH:
                return true;
            default:
                return false;
        }
    }
    @Override
    public int getOrder() {
        return -21;
    }
}